
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;

namespace WebLog
{
    public static class LoggerHelper
    {
        volatile static AsyncLocal<ConcurrentQueue<string>> AsyncSqls = new AsyncLocal<ConcurrentQueue<string>>();
        /// <summary>
        /// 本次监听的请求的路径
        /// </summary>
        volatile static AsyncLocal<string> asyncPath = new AsyncLocal<string>();
        static ConcurrentDictionary<Guid, ConcurrentQueue<string>> reqIds = new ConcurrentDictionary<Guid, ConcurrentQueue<string>>();
        /// <summary>
        /// 只有申请了监听id 才能记录日志
        /// </summary>
        /// <returns>返回监听关联的请求id</returns>
        public static Guid SetRecordAsyncSql(string path)
        {
            var id = Guid.NewGuid();
            AsyncSqls.Value = new ConcurrentQueue<string>();
            asyncPath.Value = path;
            reqIds.TryAdd(id, AsyncSqls.Value);
            return id;
        }
        /// <summary>
        /// 拿到前面所有记录的sql
        /// </summary>
        /// <returns>所有这个线程记录下来的sql</returns>
        public static List<string> DequeueSqls(Guid reqId, bool isRemove = true)
        {
            ConcurrentQueue<string> result;
            reqIds.TryRemove(reqId, out result);
            return result?.ToList();
        }
        public static string[] notSqls = new[] { "A data reader was disposed." };
        /// <summary>
        /// 记录日志 在允许记录的时候才调用
        /// </summary>
        /// <param name="getSql">产生日志的方法</param>
        public static void AppendSql(Func<string> getSql)
        {
            if (!asyncPath.Value.IsNullEmpty())
            {
                if (getSql == null) return;
                string sql = null;
                Func<string> _getSql = () => sql ?? (sql = getSql());
                _getSql();
                if (notSqls.Contains(sql)) return;
                //if (reqSqls.ContainsKey(a_reqId.Value)) 
                AsyncSqls.Value.Enqueue(sql);
                //由于这个是支持并发的容器，所以往里面新增元素无惧并发
                //因为写日志的操作是高频的 故而这里要保证效率
            }
        }
    }
}